home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
dev
/
c
/
vbcc.lha
/
vbcc
/
pasm
/
output_abs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-02-17
|
6KB
|
164 lines
/* $VER: pasm output_abs.c V0.4 (05.07.97)
*
* This file is part of pasm, a portable PowerPC assembler.
* Copyright (c) 1997-98 Frank Wille
*
* pasm is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
* pasm may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v0.4 (05.07.97) phx
* Absolute output format supports correct relocations and
* aligments. The user will be warned, if external references
* are present.
* v0.2 (25.03.97) phx
* Writes ELF object for 32-bit PowerPC big-endian. Either absolute
* or ELF output format may be selected. ELF is default for all
* currently supported platforms. PPCasm supports nine different
* relocation types (there are much more...).
* Compiles and works also under NetBSD/amiga (68k).
* Changed function declaration to 'new style' in all sources
* (to avoid problems with '...' for example).
* v0.1 (11.03.97) phx
* First test version with all PowerPC instructions and most
* important directives. Only raw, absolute output.
* v0.0 (04.03.97) phx
* File created.
*/
#define OUTPUT_ABS_C
#include "ppcasm.h"
#define BASEREG_OFFSET 0x7ffc /* @@@ ? */
void output_absolute(struct GlobalVars *);
static void wr_err(struct GlobalVars *);
void output_absolute(struct GlobalVars *gv)
{
struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
struct Reloc *nextrel,*rel;
struct XReference *xref;
unsigned long offs = gv->absbase;
FILE *fp;
/* calculate section base addresses */
while (nextsec = (struct Section *)sec->n.next) {
if (!(sec->flags & SF_DISCARD)) {
sec->index = (uint32)offs;
offs += (sec->size + 3) & ~3;
}
sec = nextsec;
}
/* create output file */
sec = (struct Section *)gv->sectionlist.first;
if (fp = fopen(gv->dest_name,"w")) {
while (nextsec = (struct Section *)sec->n.next) {
if (!(sec->flags & SF_DISCARD) && sec->size) {
/* try to resolve relocations */
rel = (struct Reloc *)sec->reloclist.first;
while (nextrel = (struct Reloc *)rel->n.next) {
uint32 *p = (uint32 *)((char *)sec->contents + rel->offset);
uint32 a = rel->relocsect->index + rel->addend;
switch (rel->type) {
case R_PPC_ADDR32:
*p = ECVW(a);
break;
case R_PPC_ADDR16:
*(uint16 *)p = ECVH((uint16)a);
break;
case R_PPC_ADDR16_LO:
*(uint16 *)p = ECVH((uint16)(a & 0xffff));
break;
case R_PPC_ADDR16_HA:
if (a & 0x8000)
a += 0x10000;
case R_PPC_ADDR16_HI:
*(uint16 *)p = ECVH((uint16)(a >> 16));
break;
case R_PPC_ADDR24:
*p = ECVW((uint32)((*(uint8 *)p & 0xfc) << 24) |
(a & 0x3fffffc) | (uint32)(*((uint8 *)p+3) & 3));
break;
case R_PPC_ADDR14:
case R_PPC_ADDR14_BRTAKEN:
case R_PPC_ADDR14_BRNTAKEN:
*((uint16 *)p+1) = ECVH((uint16)(a & 0xfffc) |
(uint16)(*((uint8 *)p+3) & 3));
break;
case R_PPC_REL24:
*p = ECVW((uint32)((*(uint8 *)p & 0xfc) << 24) |
((a - (sec->index + rel->offset)) & 0x3fffffc) |
(uint32)(*((uint8 *)p+3) & 3));
break;
case R_PPC_REL14:
case R_PPC_REL14_BRTAKEN:
case R_PPC_REL14_BRNTAKEN:
*((uint16 *)p+1) = ECVH((uint16)((a - (sec->index +
rel->offset - 2)) & 0xfffc) |
(uint16)(*((uint8 *)p+3) & 3));
break;
case R_PPC_REL32:
*p = ECVW(a - (sec->index + rel->offset));
break;
case R_PPC_TOC16:
if (gv->tocsect)
a -= gv->tocsect->index + BASEREG_OFFSET;
else
a -= BASEREG_OFFSET;
*(uint16 *)p = ECVH((uint16)a);
break;
default:
error(53,elfrel_name[rel->type & ELFRELNAMMSK],rel->offset,
sec->name); /* relocation not supported */
break;
}
rel = nextrel;
}
/* any external references? (would be difficult here :) */
while (xref = (struct XReference *)remhead(&sec->xreflist))
error(55,xref->xsymbol->name); /* no xrefs in absolute output */
/* write section contents */
if (sec->flags & SF_UNINITIALIZED) { /* bss section */
unsigned long s = (sec->size + 3) >> 2;
while (s--) {
if (!fwrite(gv->alignment_bytes,1,4,fp))
wr_err(gv);
}
}
else {
if (!fwrite(sec->contents,1,sec->size,fp))
wr_err(gv);
if ((4-(sec->size&3))&3) { /* aligment */
if (!fwrite(gv->alignment_bytes,1,(4-(sec->size&3))&3,fp))
wr_err(gv);
}
}
}
sec = nextsec;
}
fclose(fp);
}
else
error(25,gv->dest_name); /* unable to create output file */
}
static void wr_err(struct GlobalVars *gv)
{
error(26,gv->dest_name); /* write error */
}